
--
--  PvP Flag Broker
--    by Tuhljin
--


local L = PVPFLAGBROKER_STRINGS
PvPFlagBroker = {}

local GetPVPTimer = _G["GetPVPTimer"];

local def_point, def_relativeTo, def_relativePoint, def_xOfs, def_yOfs = PlayerPVPTimerText:GetPoint()

local mDisplayFormat = { "%s:%s", "%s m %s s", "%s m" }
local sDisplayFormat = { "0:%s", "%s s" }

local uncoloredText, coloredText
local TimeAtMax, QuestStuck

--local DEFAULTYELLOW  = "|cffffd100"
local GREY = "|cff8c8c8c"
local WHITE = "|cffffffff"
local COLOR_SANCTUARY = "|cff68ccef"
local COLOR_HOSTILE = "|cffff1919"
local COLOR_FRIENDLY = "|cff19ff19"
local COLOR_CONTESTED = "|cffffb200"

local iconFaction
if (UnitFactionGroup("player") == "Alliance") then
  iconFaction = "Interface\\AddOns\\PvPFlagBroker\\AllianceIcon"
else
  iconFaction = "Interface\\AddOns\\PvPFlagBroker\\HordeIcon"
end

PvPFlagBroker.DefaultSettings = {
  Version = GetAddOnMetadata("PvPFlagBroker", "Version"),
  panel = {
    DefTimer_Hide = true,
    Text_Color = true,
    Text_HideUnflagged = false,
    Icon_HideUnflagged = false,
    TogglePvPClick = true,
    TogglePvPClick_Shift = false,
    Timer_MinFormat = 1,
    Timer_SecFormat = 1,
    FFADisplay = 1,
  }
};

local ldb = LibStub:GetLibrary("LibDataBroker-1.1")
local dataobj, OptionsPanel, tipOwner


-- LOCAL FUNCTIONS
-----------------------------------

--[[
local function debugprint(msg)
  DEFAULT_CHAT_FRAME:AddMessage(msg, 1, 0.1, 0.25);
end
--]]

local function CheckPvP()
  local icon = iconFaction
  local isPvPFlagged, isPvPStuck, isPvPPermaFlag, isFFA, isFFAArea, pvpType = PvPFlagBroker.GetPvPState()
  PvPFlagBroker.PlayerIsFFA = isFFA;
  if (isPvPFlagged and not isPvPStuck) then
    if (not PvPFlagBroker.MainFrame:IsShown()) then
      PvPFlagBroker.MainFrame:Show()
    end
    if (PvPFlagBroker.PlayerIsFFA and PvPFlagBroker_Settings.panel.FFADisplay == 1) then
      uncoloredText = L.FFA_SHORT
      coloredText = COLOR_HOSTILE..L.FFA_SHORT.."|r"
    end
    if (PvPFlagBroker_Settings.panel.Text_Color) then
      dataobj.text = coloredText
    else
      dataobj.text = uncoloredText
    end
  else
    if (PvPFlagBroker.MainFrame:IsShown()) then
      PvPFlagBroker.MainFrame:Hide()
      PvPFlagBroker.TimeLeft = nil
      PvPFlagBroker.TimeLeft_m, PvPFlagBroker.TimeLeft_s = nil, nil
      TimeAtMax, QuestStuck = nil, nil
    end
    if (isFFA and PvPFlagBroker_Settings.panel.FFADisplay > 0) then
      uncoloredText = L.FFA_SHORT
      coloredText = COLOR_HOSTILE..L.FFA_SHORT.."|r"
    elseif (isPvPPermaFlag) then
      uncoloredText = L.PERMAFLAGGED
      coloredText = COLOR_CONTESTED..L.PERMAFLAGGED.."|r"
    elseif (pvpType == "hostile") then
      uncoloredText = L.HOSTILE
      coloredText = COLOR_HOSTILE..L.HOSTILE.."|r"
    elseif (isPvPStuck) then
      uncoloredText = L.CONTESTED
      coloredText = COLOR_CONTESTED..L.CONTESTED.."|r"
    else
      uncoloredText = not PvPFlagBroker_Settings.panel.Text_HideUnflagged and L.UNFLAGGED or nil
      coloredText = uncoloredText and GREY..uncoloredText.."|r" or nil
      if (PvPFlagBroker_Settings.panel.Icon_HideUnflagged) then  icon = "";  end
    end
    if (PvPFlagBroker_Settings.panel.Text_Color) then
      dataobj.text = coloredText
    else
      dataobj.text = uncoloredText
    end
  end
  if (dataobj.icon ~= icon) then  dataobj.icon = icon;  end
  if (tipOwner) then  dataobj.OnEnter(tipOwner);  end
end

local function CheckDefTimerVis()
  if (PvPFlagBroker_Settings.panel.DefTimer_Hide) then
  -- The timer is constantly re-shown by default code in PlayerFrame.lua. To compensate, we move it off screen.
    PlayerPVPTimerText:SetPoint(def_point, def_relativeTo, def_relativePoint, 0, 0)
  else
    PlayerPVPTimerText:SetPoint(def_point, def_relativeTo, def_relativePoint, def_xOfs, def_yOfs)
  end
end

local function ColorOptClick(self, key, val)
  if (val) then
    dataobj.text = coloredText
  else
    dataobj.text = uncoloredText
  end
end


-- GLOBAL FUNCTIONS
-----------------------------------

function PvPFlagBroker.GetPvPState()
  local isPvPFlagged, isPvPStuck, isPvPPermaFlag, isFFA
  if (UnitIsPVPFreeForAll("player")) then  isFFA = true;  end
  local zonepvp, isFFAArea = GetZonePVPInfo()
  if (GetPVPDesired() == 1) then
    isPvPFlagged, isPvPStuck, isPvPPermaFlag = true, true, true;
  elseif (UnitIsPVP("player")) then
    isPvPFlagged = true;
    if (zonepvp == "contested" or zonepvp == "hostile" or zonepvp == "combat") then
      isPvPStuck = true;
    else
      local _, instanceType = IsInInstance()
      if (instanceType == "pvp") then
        isPvPStuck = true;
      end
    end
  end
  return isPvPFlagged, isPvPStuck, isPvPPermaFlag, isFFA, isFFAArea, zonepvp;
end

function PvPFlagBroker.Init()
  PvPFlagBroker.MainFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
  PvPFlagBroker.MainFrame:SetScript("OnEvent", PvPFlagBroker.OnEvent)
  PvPFlagBroker.MainFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
  PvPFlagBroker.MainFrame:RegisterEvent("ZONE_CHANGED")
  PvPFlagBroker.MainFrame:RegisterEvent("UNIT_FACTION")
  PvPFlagBroker.MainFrame:RegisterEvent("CHAT_MSG_SYSTEM")

  if (not PvPFlagBroker_Settings) then
    PvPFlagBroker_Settings = {}
    local function copytab(from, to)
      for k,v in pairs(from) do
        if (type(v) == "table") then
          to[k] = {}
          copytab(v, to[k])
        else
          to[k] = v
        end
      end
    end
    copytab(PvPFlagBroker.DefaultSettings, PvPFlagBroker_Settings)
  else
    if (PvPFlagBroker_Settings.Version ~= PvPFlagBroker.DefaultSettings.Version) then
      PvPFlagBroker_Settings.Version = PvPFlagBroker.DefaultSettings.Version
      local panel = PvPFlagBroker_Settings.panel
      for k,v in pairs(PvPFlagBroker.DefaultSettings.panel) do
      -- Add options new to this version, set to default:
        if (panel[k] == nil) then  panel[k] = v;  end
      end
    end
  end
  CheckDefTimerVis()

  local colortip2 = GREY..L.UNFLAGGED.."|n"..
    WHITE..L.OPT_COLOR_TIP_DROPPING.."|n"..
    COLOR_CONTESTED..L.OPT_COLOR_TIP_CONTESTED.."|n"..
    L.OPT_COLOR_TIP_PERMAFLAGGED.."|n"..
    L.PVPQUEST.."|n"..
    COLOR_HOSTILE..L.OPT_COLOR_TIP_HOSTILE.."|n"..
    L.FFA;

  local FFA_DropdownMenu = {
    {
      text = L.OPT_FFA_OVERRIDE,
      tooltipTitle = L.OPT_FFA_OVERRIDE,
      tooltipText = L.OPT_FFA_OVERRIDE_TIP,
      value = 1
    },
    {
      text = L.OPT_FFA_OVERRIDESTATIC,
      tooltipTitle = L.OPT_FFA_OVERRIDESTATIC,
      tooltipText = L.OPT_FFA_OVERRIDESTATIC_TIP,
      value = 2
    },
    {
      text = L.OPT_FFA_COLORTIMER,
      tooltipTitle = L.OPT_FFA_COLORTIMER,
      tooltipText = L.OPT_FFA_COLORTIMER_TIP,
      value = 3
    },
    {
      text = L.OPT_FFA_NONE,
      tooltipTitle = L.OPT_FFA_NONE,
      tooltipText = L.OPT_FFA_NONE_TIP,
      value = 0
    };
  };

  local minTimer_DropdownMenu = {
    {
      text = L.OPT_MINFORMAT_A,
      value = 1
    },
    {
      text = L.OPT_MINFORMAT_B,
      value = 2
    },
    {
      text = L.OPT_MINFORMAT_C,
      value = 3
    };
  };
  local secTimer_DropdownMenu = {
    {
      text = L.OPT_SECFORMAT_A,
      value = 1
    },
    {
      text = L.OPT_SECFORMAT_B,
      value = 2
    };
  };

  local panelContents = {
  	title = "PvP Flag Broker",
  	items = {
  		 { variable = "DefTimer_Hide", text = L.OPT_HIDEDEF,
  		   tooltip = L.OPT_HIDEDEF_TIP, OnChange = CheckDefTimerVis },
  		 { variable = "Text_Color", text = L.OPT_COLOR,
  		   tooltip = L.OPT_COLOR_TIP, tooltip2 = colortip2, OnChange = ColorOptClick },
  		 { variable = "Text_HideUnflagged", text = L.OPT_UNFLAGGED_TEXTDISPLAY_NONE, OnChange = CheckPvP },
  		 { variable = "Icon_HideUnflagged", text = L.OPT_UNFLAGGED_ICON_NONE, OnChange = CheckPvP },
  		 { variable = "TogglePvPClick", text = L.OPT_TOGGLEPVP },
  		 { variable = "TogglePvPClick_Shift", text = L.OPT_TOGGLEPVP_SHIFT, xOffset = 10 },
  		 { variable = "FFADisplay", type = "dropdown", text = L.OPT_FFA_LABEL,
  		   menu = FFA_DropdownMenu, width = 105, OnChange = CheckPvP, xOffset = 0 },
  		 { type = "labelwhite", text = L.OPT_FORMAT_LABEL, topBuffer = 10 },
  		 { variable = "Timer_MinFormat", type = "dropdown", text = L.OPT_MINFORMAT_LABEL,
  		   menu = minTimer_DropdownMenu, width = 95, xOffset = 10 },
  		 { variable = "Timer_SecFormat", type = "dropdown", text = L.OPT_SECFORMAT_LABEL,
  		   menu = secTimer_DropdownMenu, width = 95},
  	},
  	variables = PvPFlagBroker_Settings.panel,
  	defaults = PvPFlagBroker.DefaultSettings.panel
  };
  OptionsPanel = TjOptions.CreatePanel("PvP Flag Broker", nil, panelContents);

  CheckPvP()
  PvPFlagBroker.Init = nil;
end

function PvPFlagBroker.OnEvent(self, event, arg1)
  if ( event == "ZONE_CHANGED_NEW_AREA" or event == "ZONE_CHANGED" or
       (event == "UNIT_FACTION" and arg1 == "player") or
       (event == "CHAT_MSG_SYSTEM" and (arg1 == PVP_TOGGLE_ON_VERBOSE or arg1 == PVP_TOGGLE_OFF_VERBOSE)) ) then
    --debugprint("  "..event)
    CheckPvP()
  end
end

function PvPFlagBroker.OnClick(self, button)
  if (button == "LeftButton") then
    if ( PvPFlagBroker_Settings.panel.TogglePvPClick and
         (not PvPFlagBroker_Settings.panel.TogglePvPClick_Shift or IsShiftKeyDown()) ) then
      TogglePVP()
    end
  else
    PlaySound("igMainMenuOption")
    InterfaceOptionsFrame_OpenToCategory(OptionsPanel)
  end
end


-- FRAME & DATA OBJECT INITIALIZATION
---------------------------------------

PvPFlagBroker.MainFrame = CreateFrame("Frame")
PvPFlagBroker.MainFrame:Hide()
PvPFlagBroker.MainFrame:SetScript("OnEvent", PvPFlagBroker.Init)
PvPFlagBroker.MainFrame:RegisterEvent("PLAYER_ENTERING_WORLD")

PvPFlagBroker.MainFrame:SetScript("OnUpdate", function()
  local timeLeft = floor(GetPVPTimer() / 1000)
  if (timeLeft ~= PvPFlagBroker.TimeLeft) then
    if (timeLeft == 301) then
      TimeAtMax = time()
    else
      TimeAtMax = nil
    end
    QuestStuck = nil

    PvPFlagBroker.TimeLeft = timeLeft
    local m, s
    if (timeLeft < 0) then
      m, s = "?", "??"
      PvPFlagBroker.TimeLeft_m, PvPFlagBroker.TimeLeft_s = m, s
    else
      m = floor(timeLeft / 60)
      s = timeLeft - (m * 60)
      PvPFlagBroker.TimeLeft_m, PvPFlagBroker.TimeLeft_s = m, s
      if ( s < 10 and ((m == 0 and PvPFlagBroker_Settings.panel.Timer_SecFormat == 1) or
           (m > 0 and PvPFlagBroker_Settings.panel.Timer_MinFormat == 1)) ) then
        s = "0"..s
      end
    end
    if (not PvPFlagBroker.PlayerIsFFA or PvPFlagBroker_Settings.panel.FFADisplay ~= 1) then
      if (m == "?" or m > 0) then
        if (PvPFlagBroker_Settings.panel.Timer_MinFormat == 3) then
          local i = m
          if (s ~= "??" and PvPFlagBroker.TimeLeft_s > 0) then  i = i + 1;  end
          uncoloredText = mDisplayFormat[3]:format(i)
        else
          uncoloredText = mDisplayFormat[PvPFlagBroker_Settings.panel.Timer_MinFormat]:format(m, s)
        end
      else
        uncoloredText = sDisplayFormat[PvPFlagBroker_Settings.panel.Timer_SecFormat]:format(s)
      end
      if (PvPFlagBroker.PlayerIsFFA and PvPFlagBroker_Settings.panel.FFADisplay == 3) then
        coloredText = COLOR_HOSTILE..uncoloredText.."|r"
        uncoloredText = coloredText  -- Special case, always colored.
      else
        coloredText = WHITE..uncoloredText.."|r"
      end
      if (PvPFlagBroker_Settings.panel.Text_Color) then
        dataobj.text = coloredText
      else
        dataobj.text = uncoloredText
      end
      if (tipOwner) then  dataobj.OnEnter(tipOwner);  end
    end
    
  -- Check if we're stuck at the max timer:
  elseif (TimeAtMax and not QuestStuck and time() > TimeAtMax + 2) then
    -- The +2 generally prevents "Quest" from showing when it shouldn't (at the expense of showing it when it
    -- should more quickly, but this seems preferable).
    QuestStuck = true
    uncoloredText = L.PVPQUEST_SHORT
    coloredText = COLOR_CONTESTED..uncoloredText.."|r"
    if (PvPFlagBroker_Settings.panel.Text_Color) then
      dataobj.text = coloredText
    else
      dataobj.text = uncoloredText
    end
    if (tipOwner) then  dataobj.OnEnter(tipOwner);  end
  end
end)

dataobj = ldb:NewDataObject("PvPFlag", {
  type = "data source",
  icon = iconFaction,
  label = "PvP",
  text = "?",
  OnClick = PvPFlagBroker.OnClick,
  -- For Titan Panel:
  tocname = "PvPFlagBroker"
})

local QuestFlagsPvP = {  -- Quests known to flag you for PvP
-- Grizzled Veteran dailies:
  -- Alliance:
  [12444] = true, [12296] = true, [12289] = true, [12314] = true, [12437] = true, [12268] = true,
  [12244] = true, [12323] = true,
  -- Horde:
  [12170] = true, [12280] = true, [12288] = true, [12315] = true, [12324] = true, [12270] = true,
  [12284] = true, [12432] = true,
  -- Note that "Keep Them at Bay(!)" is omitted. The Alliance version, at least, doesn't auto-flag you.
  -- (Always) Seeking Solvent:
  [12443] = true, [12446] = true, [12433] = true, [12434] = true
}

local function OnTooltipShow(tooltip)
  tooltip:AddLine(WHITE.."PvP Flag Broker")
  local text
  local isPvPFlagged, isPvPStuck, isPvPPermaFlag, isFFA, isFFAArea, pvpType = PvPFlagBroker.GetPvPState()

  local pvpstatus
  if (isFFA) then
    tooltip:AddDoubleLine(L.TIP_STATUS, COLOR_HOSTILE..L.FFA)
    pvpstatus = L.TIP_CROSSFACTION
  end
  local m, s
  if (isPvPFlagged) then
    if (isPvPPermaFlag) then
      text = COLOR_HOSTILE..L.TIP_PERMAFLAGGED
    elseif (QuestStuck) then
      text = COLOR_HOSTILE..L.PVPQUEST
    elseif (isPvPStuck) then
      text = COLOR_HOSTILE..L.TIP_STUCK
    else
      text = COLOR_CONTESTED..L.TIP_DROPPING
      m, s = PvPFlagBroker.TimeLeft_m, PvPFlagBroker.TimeLeft_s
    end
  else
    text = COLOR_FRIENDLY..L.TIP_UNFLAGGED
  end
  tooltip:AddDoubleLine(pvpstatus or L.TIP_STATUS, text)
  if (m) then
    local rem
    if (m == 0) then
      rem = sDisplayFormat[2]:format(s)
    else
      rem = mDisplayFormat[2]:format(m, s)
    end
    tooltip:AddDoubleLine(WHITE.."- "..L.TIP_DROPPING_MS, WHITE..rem)
  end

  if (QuestStuck or isPvPStuck) then
    local heading = QuestStuck
    for id,tab in pairs(TjQuestLog.GetDataTable()) do
      if (QuestFlagsPvP[id]) then
        if (not heading) then  -- If the PvP Quest label isn't already used:
          tooltip:AddLine(L.TIP_PVPQUESTS)
          heading = true
        end
        tooltip:AddLine("- "..tab.questTitle, 1, 1, 1)
      end
    end
  end

  if (pvpType == "sanctuary") then
    text = COLOR_SANCTUARY..L.SANCTUARY
  elseif (pvpType == "combat") then
    text = COLOR_CONTESTED..L.COMBAT
  elseif (isFFAArea or pvpType == "arena") then
    if (IsInInstance()) then
      text = COLOR_HOSTILE..L.ARENA
    else
      text = COLOR_HOSTILE..L.FFA
    end
  elseif (pvpType == "hostile") then
    text = COLOR_HOSTILE..L.HOSTILE
  elseif (pvpType == "friendly") then
    text = COLOR_FRIENDLY..L.FRIENDLY
  else
    local _, instanceType = IsInInstance()
    if (instanceType == "pvp") then
      text = COLOR_CONTESTED..L.BG
    elseif (not pvpType) then
      text = COLOR_CONTESTED..L.NEUTRAL
    else
      text = COLOR_CONTESTED..L.CONTESTED
    end
  end
  tooltip:AddDoubleLine(L.TIP_AREA, text)
  tooltip:AddLine(" ")
  if (PvPFlagBroker_Settings.panel.TogglePvPClick) then
    if (PvPFlagBroker_Settings.panel.TogglePvPClick_Shift) then
      tooltip:AddLine(COLOR_FRIENDLY..L.TIP_LEFTCLICK_SHIFT)
    else
      tooltip:AddLine(COLOR_FRIENDLY..L.TIP_LEFTCLICK)
    end
  end
  tooltip:AddLine(COLOR_FRIENDLY..L.TIP_RIGHTCLICK)
end

function dataobj.OnEnter(self)
  local leftright, topbtm, topbtm2 = ""
  local x, y = self:GetCenter();
  local w, h = UIParent:GetWidth() / 3, UIParent:GetHeight() / 2
  if (x < w) then
    leftright = "LEFT"
  elseif (x > w * 2) then
    leftright = "RIGHT"
  end
  if (y < h) then
    topbtm, topbtm2 = "BOTTOM", "TOP";
  else
    topbtm, topbtm2 = "TOP", "BOTTOM";
  end
  GameTooltip:SetOwner(self, "ANCHOR_NONE")
  GameTooltip:SetPoint(topbtm..leftright, self, topbtm2..leftright)
  OnTooltipShow(GameTooltip)
  GameTooltip:Show()
  tipOwner = self
end

function dataobj.OnLeave()
  GameTooltip:Hide()
  tipOwner = nil
end
